#!/opt/python2.7/bin/python
##
#    HTML Tools Class
#         
#    Provides a set of basic tools to work with html
#    
#    @author     David Lasley, dave -at- dlasley -dot- net
#    @package    html-tools
#    @version    $Id$
import urllib2

class html_tools(object):    
    @staticmethod
    def html5_parser(tree_type='dom'):
        '''
            Return an html5lib HTMLParser of the selected tree type
            
            @param  String  tree_type   Tree type to return
            
            @return html5lib.HTMLParser
        '''
        import html5lib
        from html5lib import treebuilders
        return html5lib.HTMLParser(tree=treebuilders.getTreeBuilder(tree_type))

    @staticmethod
    def url_retriever(auth_handler=None):
        ''' Return urllib2.OpenerDirector object with cookies '''
        import cookielib
        if auth_handler is not None:
            return urllib2.build_opener(urllib2.HTTPCookieProcessor(cookielib.CookieJar()),auth_handler)
        else:
            return urllib2.build_opener(urllib2.HTTPCookieProcessor(cookielib.CookieJar()))
    
    @staticmethod
    def url_retriever_auth(host,username,password):
        '''
            Return urllib2.OpenerDirector with cookies and auth handler
            
            @param  String  host        Host
            @param  String  username    Login username
            @param  String  password    Login password
            
            @return urllib2.OpenerDirector
        '''
        passman = urllib2.HTTPPasswordMgrWithDefaultRealm()
        passman.add_password(None,host,username,password)
        auth_handler = urllib2.HTTPBasicAuthHandler(passman)
        return html_tools.url_retriever(auth_handler)
    
    @staticmethod
    def url_encode(data):
        '''
            URL encode a dictionary
            
            @param  Dict    data    Dictionary of values to URL encode
            @return String  URL encoded string
        '''
        outstr = []
        for key,single in data.iteritems():
            outstr.append('%s=%s'%(urllib2.quote(str(key)),urllib2.quote(str(single))))
        return '&'.join(outstr)
    
    @staticmethod
    def url_open(obj,url,data=None,timeout=500,loop_times=4):
        '''
            Open a url, throw error if fail
            
            @param  urllib2.urlopener   obj         URL opener obj
            @param  str                 url         URL to open
            @param  str                 data        Data to pass
            @param  int                 loop_times  Added to duct-tape #370, self-explanatory
            
            @return str Page as string
        '''
        for i in xrange(0,loop_times):
            try: return obj.open(url,data,timeout)
            except urllib2.URLError: pass
        raise Exception('URL Open Error',message='Failed to open URL "%s" with request data "%s"' % (url,data))
    
    @staticmethod
    def parse_table(table,verify,allow_blanks=[],row_tag='tr',col_tag='td'):
        '''
            This function is a generic table parser
            
            @param  DOMNodeList table           table to search
            @param  String      verify          Table column header that must be numeric
            @param  List        allow_blanks    List of table column headers that can have blank data but still be valid
            
            @return List    List of dictionaries containing parsed table in header:value format
        '''
        for row in table.getElementsByTagName(row_tag):
            cols = row.getElementsByTagName(col_tag)
            try:
                parsed_table
                parsed_row = {}
                col_cnt = 0
                for col_key in xrange(0,cols.length):
                    if cols.item(col_key).hasChildNodes():
                        for child in cols[col_key].childNodes:
                            try:
                                value = child.nodeValue.strip()
                                if value != '':
                                    try:
                                        parsed_row[headers[col_cnt]] = value
                                        col_cnt+=1
                                    except IndexError:
                                        print headers,col_cnt,value,parsed_row
                                    break
                            except AttributeError:
                                pass
                        else:
                            try:
                                if headers[col_cnt] in allow_blanks:
                                    try:
                                        parsed_row[headers[col_cnt]]
                                    except KeyError:
                                        parsed_row[headers[col_cnt]] = ''
                                        col_cnt+=1
                            except IndexError:
                                pass
                try:
                    if parsed_row[verify].isdigit(): parsed_table.append(parsed_row)
                except KeyError:
                    pass
            except NameError:
                parsed_table = []
                headers = []
                for col in cols:
                    if col.hasChildNodes():
                        try:
                            value = col.firstChild.nodeValue.strip()
                            headers.append(value)
                        except AttributeError:
                            pass
        return parsed_table